home *** CD-ROM | disk | FTP | other *** search
/ Freelog 100 / FreelogNo100-NovembreDecembre2010.iso / Musique / solfege / solfege-win32-3.17.0.exe / {app} / bin / Lib / bsddb / test / test_basics.py < prev    next >
Text File  |  2006-09-12  |  30KB  |  990 lines

  1. """
  2. Basic TestCases for BTree and hash DBs, with and without a DBEnv, with
  3. various DB flags, etc.
  4. """
  5.  
  6. import os
  7. import sys
  8. import errno
  9. import shutil
  10. import string
  11. import tempfile
  12. from pprint import pprint
  13. import unittest
  14. import time
  15.  
  16. try:
  17.     # For Pythons w/distutils pybsddb
  18.     from bsddb3 import db
  19. except ImportError:
  20.     # For Python 2.3
  21.     from bsddb import db
  22.  
  23. from test_all import verbose
  24.  
  25. DASH = '-'
  26.  
  27.  
  28. #----------------------------------------------------------------------
  29.  
  30. class VersionTestCase(unittest.TestCase):
  31.     def test00_version(self):
  32.         info = db.version()
  33.         if verbose:
  34.             print '\n', '-=' * 20
  35.             print 'bsddb.db.version(): %s' % (info, )
  36.             print db.DB_VERSION_STRING
  37.             print '-=' * 20
  38.         assert info == (db.DB_VERSION_MAJOR, db.DB_VERSION_MINOR,
  39.                         db.DB_VERSION_PATCH)
  40.  
  41. #----------------------------------------------------------------------
  42.  
  43. class BasicTestCase(unittest.TestCase):
  44.     dbtype       = db.DB_UNKNOWN  # must be set in derived class
  45.     dbopenflags  = 0
  46.     dbsetflags   = 0
  47.     dbmode       = 0660
  48.     dbname       = None
  49.     useEnv       = 0
  50.     envflags     = 0
  51.     envsetflags  = 0
  52.  
  53.     _numKeys      = 1002    # PRIVATE.  NOTE: must be an even value
  54.  
  55.     def setUp(self):
  56.         if self.useEnv:
  57.             homeDir = os.path.join(os.path.dirname(sys.argv[0]), 'db_home')
  58.             self.homeDir = homeDir
  59.             try:
  60.                 shutil.rmtree(homeDir)
  61.             except OSError, e:
  62.                 # unix returns ENOENT, windows returns ESRCH
  63.                 if e.errno not in (errno.ENOENT, errno.ESRCH): raise
  64.             os.mkdir(homeDir)
  65.             try:
  66.                 self.env = db.DBEnv()
  67.                 self.env.set_lg_max(1024*1024)
  68.                 self.env.set_tx_max(30)
  69.                 self.env.set_tx_timestamp(int(time.time()))
  70.                 self.env.set_flags(self.envsetflags, 1)
  71.                 self.env.open(homeDir, self.envflags | db.DB_CREATE)
  72.                 tempfile.tempdir = homeDir
  73.                 self.filename = os.path.split(tempfile.mktemp())[1]
  74.                 tempfile.tempdir = None
  75.             # Yes, a bare except is intended, since we're re-raising the exc.
  76.             except:
  77.                 shutil.rmtree(homeDir)
  78.                 raise
  79.         else:
  80.             self.env = None
  81.             self.filename = tempfile.mktemp()
  82.  
  83.         # create and open the DB
  84.         self.d = db.DB(self.env)
  85.         self.d.set_flags(self.dbsetflags)
  86.         if self.dbname:
  87.             self.d.open(self.filename, self.dbname, self.dbtype,
  88.                         self.dbopenflags|db.DB_CREATE, self.dbmode)
  89.         else:
  90.             self.d.open(self.filename,   # try out keyword args
  91.                         mode = self.dbmode,
  92.                         dbtype = self.dbtype,
  93.                         flags = self.dbopenflags|db.DB_CREATE)
  94.  
  95.         self.populateDB()
  96.  
  97.  
  98.     def tearDown(self):
  99.         self.d.close()
  100.         if self.env is not None:
  101.             self.env.close()
  102.             shutil.rmtree(self.homeDir)
  103.             ## Make a new DBEnv to remove the env files from the home dir.
  104.             ## (It can't be done while the env is open, nor after it has been
  105.             ## closed, so we make a new one to do it.)
  106.             #e = db.DBEnv()
  107.             #e.remove(self.homeDir)
  108.             #os.remove(os.path.join(self.homeDir, self.filename))
  109.         else:
  110.             os.remove(self.filename)
  111.  
  112.  
  113.  
  114.     def populateDB(self, _txn=None):
  115.         d = self.d
  116.  
  117.         for x in range(self._numKeys/2):
  118.             key = '%04d' % (self._numKeys - x)  # insert keys in reverse order
  119.             data = self.makeData(key)
  120.             d.put(key, data, _txn)
  121.  
  122.         d.put('empty value', '', _txn)
  123.  
  124.         for x in range(self._numKeys/2-1):
  125.             key = '%04d' % x  # and now some in forward order
  126.             data = self.makeData(key)
  127.             d.put(key, data, _txn)
  128.  
  129.         if _txn:
  130.             _txn.commit()
  131.  
  132.         num = len(d)
  133.         if verbose:
  134.             print "created %d records" % num
  135.  
  136.  
  137.     def makeData(self, key):
  138.         return DASH.join([key] * 5)
  139.  
  140.  
  141.  
  142.     #----------------------------------------
  143.  
  144.     def test01_GetsAndPuts(self):
  145.         d = self.d
  146.  
  147.         if verbose:
  148.             print '\n', '-=' * 30
  149.             print "Running %s.test01_GetsAndPuts..." % self.__class__.__name__
  150.  
  151.         for key in ['0001', '0100', '0400', '0700', '0999']:
  152.             data = d.get(key)
  153.             if verbose:
  154.                 print data
  155.  
  156.         assert d.get('0321') == '0321-0321-0321-0321-0321'
  157.  
  158.         # By default non-existant keys return None...
  159.         assert d.get('abcd') == None
  160.  
  161.         # ...but they raise exceptions in other situations.  Call
  162.         # set_get_returns_none() to change it.
  163.         try:
  164.             d.delete('abcd')
  165.         except db.DBNotFoundError, val:
  166.             assert val[0] == db.DB_NOTFOUND
  167.             if verbose: print val
  168.         else:
  169.             self.fail("expected exception")
  170.  
  171.  
  172.         d.put('abcd', 'a new record')
  173.         assert d.get('abcd') == 'a new record'
  174.  
  175.         d.put('abcd', 'same key')
  176.         if self.dbsetflags & db.DB_DUP:
  177.             assert d.get('abcd') == 'a new record'
  178.         else:
  179.             assert d.get('abcd') == 'same key'
  180.  
  181.  
  182.         try:
  183.             d.put('abcd', 'this should fail', flags=db.DB_NOOVERWRITE)
  184.         except db.DBKeyExistError, val:
  185.             assert val[0] == db.DB_KEYEXIST
  186.             if verbose: print val
  187.         else:
  188.             self.fail("expected exception")
  189.  
  190.         if self.dbsetflags & db.DB_DUP:
  191.             assert d.get('abcd') == 'a new record'
  192.         else:
  193.             assert d.get('abcd') == 'same key'
  194.  
  195.  
  196.         d.sync()
  197.         d.close()
  198.         del d
  199.  
  200.         self.d = db.DB(self.env)
  201.         if self.dbname:
  202.             self.d.open(self.filename, self.dbname)
  203.         else:
  204.             self.d.open(self.filename)
  205.         d = self.d
  206.  
  207.         assert d.get('0321') == '0321-0321-0321-0321-0321'
  208.         if self.dbsetflags & db.DB_DUP:
  209.             assert d.get('abcd') == 'a new record'
  210.         else:
  211.             assert d.get('abcd') == 'same key'
  212.  
  213.         rec = d.get_both('0555', '0555-0555-0555-0555-0555')
  214.         if verbose:
  215.             print rec
  216.  
  217.         assert d.get_both('0555', 'bad data') == None
  218.  
  219.         # test default value
  220.         data = d.get('bad key', 'bad data')
  221.         assert data == 'bad data'
  222.  
  223.         # any object can pass through
  224.         data = d.get('bad key', self)
  225.         assert data == self
  226.  
  227.         s = d.stat()
  228.         assert type(s) == type({})
  229.         if verbose:
  230.             print 'd.stat() returned this dictionary:'
  231.             pprint(s)
  232.  
  233.  
  234.     #----------------------------------------
  235.  
  236.     def test02_DictionaryMethods(self):
  237.         d = self.d
  238.  
  239.         if verbose:
  240.             print '\n', '-=' * 30
  241.             print "Running %s.test02_DictionaryMethods..." % \
  242.                   self.__class__.__name__
  243.  
  244.         for key in ['0002', '0101', '0401', '0701', '0998']:
  245.             data = d[key]
  246.             assert data == self.makeData(key)
  247.             if verbose:
  248.                 print data
  249.  
  250.         assert len(d) == self._numKeys
  251.         keys = d.keys()
  252.         assert len(keys) == self._numKeys
  253.         assert type(keys) == type([])
  254.  
  255.         d['new record'] = 'a new record'
  256.         assert len(d) == self._numKeys+1
  257.         keys = d.keys()
  258.         assert len(keys) == self._numKeys+1
  259.  
  260.         d['new record'] = 'a replacement record'
  261.         assert len(d) == self._numKeys+1
  262.         keys = d.keys()
  263.         assert len(keys) == self._numKeys+1
  264.  
  265.         if verbose:
  266.             print "the first 10 keys are:"
  267.             pprint(keys[:10])
  268.  
  269.         assert d['new record'] == 'a replacement record'
  270.  
  271.         assert d.has_key('0001') == 1
  272.         assert d.has_key('spam') == 0
  273.  
  274.         items = d.items()
  275.         assert len(items) == self._numKeys+1
  276.         assert type(items) == type([])
  277.         assert type(items[0]) == type(())
  278.         assert len(items[0]) == 2
  279.  
  280.         if verbose:
  281.             print "the first 10 items are:"
  282.             pprint(items[:10])
  283.  
  284.         values = d.values()
  285.         assert len(values) == self._numKeys+1
  286.         assert type(values) == type([])
  287.  
  288.         if verbose:
  289.             print "the first 10 values are:"
  290.             pprint(values[:10])
  291.  
  292.  
  293.  
  294.     #----------------------------------------
  295.  
  296.     def test03_SimpleCursorStuff(self, get_raises_error=0, set_raises_error=0):
  297.         if verbose:
  298.             print '\n', '-=' * 30
  299.             print "Running %s.test03_SimpleCursorStuff (get_error %s, set_error %s)..." % \
  300.                   (self.__class__.__name__, get_raises_error, set_raises_error)
  301.  
  302.         if self.env and self.dbopenflags & db.DB_AUTO_COMMIT:
  303.             txn = self.env.txn_begin()
  304.         else:
  305.             txn = None
  306.         c = self.d.cursor(txn=txn)
  307.  
  308.         rec = c.first()
  309.         count = 0
  310.         while rec is not None:
  311.             count = count + 1
  312.             if verbose and count % 100 == 0:
  313.                 print rec
  314.             try:
  315.                 rec = c.next()
  316.             except db.DBNotFoundError, val:
  317.                 if get_raises_error:
  318.                     assert val[0] == db.DB_NOTFOUND
  319.                     if verbose: print val
  320.                     rec = None
  321.                 else:
  322.                     self.fail("unexpected DBNotFoundError")
  323.             assert c.get_current_size() == len(c.current()[1]), "%s != len(%r)" % (c.get_current_size(), c.current()[1])
  324.  
  325.         assert count == self._numKeys
  326.  
  327.  
  328.         rec = c.last()
  329.         count = 0
  330.         while rec is not None:
  331.             count = count + 1
  332.             if verbose and count % 100 == 0:
  333.                 print rec
  334.             try:
  335.                 rec = c.prev()
  336.             except db.DBNotFoundError, val:
  337.                 if get_raises_error:
  338.                     assert val[0] == db.DB_NOTFOUND
  339.                     if verbose: print val
  340.                     rec = None
  341.                 else:
  342.                     self.fail("unexpected DBNotFoundError")
  343.  
  344.         assert count == self._numKeys
  345.  
  346.         rec = c.set('0505')
  347.         rec2 = c.current()
  348.         assert rec == rec2
  349.         assert rec[0] == '0505'
  350.         assert rec[1] == self.makeData('0505')
  351.         assert c.get_current_size() == len(rec[1])
  352.  
  353.         # make sure we get empty values properly
  354.         rec = c.set('empty value')
  355.         assert rec[1] == ''
  356.         assert c.get_current_size() == 0
  357.  
  358.         try:
  359.             n = c.set('bad key')
  360.         except db.DBNotFoundError, val:
  361.             assert val[0] == db.DB_NOTFOUND
  362.             if verbose: print val
  363.         else:
  364.             if set_raises_error:
  365.                 self.fail("expected exception")
  366.             if n != None:
  367.                 self.fail("expected None: %r" % (n,))
  368.  
  369.         rec = c.get_both('0404', self.makeData('0404'))
  370.         assert rec == ('0404', self.makeData('0404'))
  371.  
  372.         try:
  373.             n = c.get_both('0404', 'bad data')
  374.         except db.DBNotFoundError, val:
  375.             assert val[0] == db.DB_NOTFOUND
  376.             if verbose: print val
  377.         else:
  378.             if get_raises_error:
  379.                 self.fail("expected exception")
  380.             if n != None:
  381.                 self.fail("expected None: %r" % (n,))
  382.  
  383.         if self.d.get_type() == db.DB_BTREE:
  384.             rec = c.set_range('011')
  385.             if verbose:
  386.                 print "searched for '011', found: ", rec
  387.  
  388.             rec = c.set_range('011',dlen=0,doff=0)
  389.             if verbose:
  390.                 print "searched (partial) for '011', found: ", rec
  391.             if rec[1] != '': self.fail('expected empty data portion')
  392.  
  393.             ev = c.set_range('empty value')
  394.             if verbose:
  395.                 print "search for 'empty value' returned", ev
  396.             if ev[1] != '': self.fail('empty value lookup failed')
  397.  
  398.         c.set('0499')
  399.         c.delete()
  400.         try:
  401.             rec = c.current()
  402.         except db.DBKeyEmptyError, val:
  403.             if get_raises_error:
  404.                 assert val[0] == db.DB_KEYEMPTY
  405.                 if verbose: print val
  406.             else:
  407.                 self.fail("unexpected DBKeyEmptyError")
  408.         else:
  409.             if get_raises_error:
  410.                 self.fail('DBKeyEmptyError exception expected')
  411.  
  412.         c.next()
  413.         c2 = c.dup(db.DB_POSITION)
  414.         assert c.current() == c2.current()
  415.  
  416.         c2.put('', 'a new value', db.DB_CURRENT)
  417.         assert c.current() == c2.current()
  418.         assert c.current()[1] == 'a new value'
  419.  
  420.         c2.put('', 'er', db.DB_CURRENT, dlen=0, doff=5)
  421.         assert c2.current()[1] == 'a newer value'
  422.  
  423.         c.close()
  424.         c2.close()
  425.         if txn:
  426.             txn.commit()
  427.  
  428.         # time to abuse the closed cursors and hope we don't crash
  429.         methods_to_test = {
  430.             'current': (),
  431.             'delete': (),
  432.             'dup': (db.DB_POSITION,),
  433.             'first': (),
  434.             'get': (0,),
  435.             'next': (),
  436.             'prev': (),
  437.             'last': (),
  438.             'put':('', 'spam', db.DB_CURRENT),
  439.             'set': ("0505",),
  440.         }
  441.         for method, args in methods_to_test.items():
  442.             try:
  443.                 if verbose:
  444.                     print "attempting to use a closed cursor's %s method" % \
  445.                           method
  446.                 # a bug may cause a NULL pointer dereference...
  447.                 apply(getattr(c, method), args)
  448.             except db.DBError, val:
  449.                 assert val[0] == 0
  450.                 if verbose: print val
  451.             else:
  452.                 self.fail("no exception raised when using a buggy cursor's"
  453.                           "%s method" % method)
  454.  
  455.         #
  456.         # free cursor referencing a closed database, it should not barf:
  457.         #
  458.         oldcursor = self.d.cursor(txn=txn)
  459.         self.d.close()
  460.  
  461.         # this would originally cause a segfault when the cursor for a
  462.         # closed database was cleaned up.  it should not anymore.
  463.         # SF pybsddb bug id 667343
  464.         del oldcursor
  465.  
  466.     def test03b_SimpleCursorWithoutGetReturnsNone0(self):
  467.         # same test but raise exceptions instead of returning None
  468.         if verbose:
  469.             print '\n', '-=' * 30
  470.             print "Running %s.test03b_SimpleCursorStuffWithoutGetReturnsNone..." % \
  471.                   self.__class__.__name__
  472.  
  473.         old = self.d.set_get_returns_none(0)
  474.         assert old == 2
  475.         self.test03_SimpleCursorStuff(get_raises_error=1, set_raises_error=1)
  476.  
  477.     def test03b_SimpleCursorWithGetReturnsNone1(self):
  478.         # same test but raise exceptions instead of returning None
  479.         if verbose:
  480.             print '\n', '-=' * 30
  481.             print "Running %s.test03b_SimpleCursorStuffWithoutGetReturnsNone..." % \
  482.                   self.__class__.__name__
  483.  
  484.         old = self.d.set_get_returns_none(1)
  485.         self.test03_SimpleCursorStuff(get_raises_error=0, set_raises_error=1)
  486.  
  487.  
  488.     def test03c_SimpleCursorGetReturnsNone2(self):
  489.         # same test but raise exceptions instead of returning None
  490.         if verbose:
  491.             print '\n', '-=' * 30
  492.             print "Running %s.test03c_SimpleCursorStuffWithoutSetReturnsNone..." % \
  493.                   self.__class__.__name__
  494.  
  495.         old = self.d.set_get_returns_none(1)
  496.         assert old == 2
  497.         old = self.d.set_get_returns_none(2)
  498.         assert old == 1
  499.         self.test03_SimpleCursorStuff(get_raises_error=0, set_raises_error=0)
  500.  
  501.     #----------------------------------------
  502.  
  503.     def test04_PartialGetAndPut(self):
  504.         d = self.d
  505.         if verbose:
  506.             print '\n', '-=' * 30
  507.             print "Running %s.test04_PartialGetAndPut..." % \
  508.                   self.__class__.__name__
  509.  
  510.         key = "partialTest"
  511.         data = "1" * 1000 + "2" * 1000
  512.         d.put(key, data)
  513.         assert d.get(key) == data
  514.         assert d.get(key, dlen=20, doff=990) == ("1" * 10) + ("2" * 10)
  515.  
  516.         d.put("partialtest2", ("1" * 30000) + "robin" )
  517.         assert d.get("partialtest2", dlen=5, doff=30000) == "robin"
  518.  
  519.         # There seems to be a bug in DB here...  Commented out the test for
  520.         # now.
  521.         ##assert d.get("partialtest2", dlen=5, doff=30010) == ""
  522.  
  523.         if self.dbsetflags != db.DB_DUP:
  524.             # Partial put with duplicate records requires a cursor
  525.             d.put(key, "0000", dlen=2000, doff=0)
  526.             assert d.get(key) == "0000"
  527.  
  528.             d.put(key, "1111", dlen=1, doff=2)
  529.             assert d.get(key) == "0011110"
  530.  
  531.     #----------------------------------------
  532.  
  533.     def test05_GetSize(self):
  534.         d = self.d
  535.         if verbose:
  536.             print '\n', '-=' * 30
  537.             print "Running %s.test05_GetSize..." % self.__class__.__name__
  538.  
  539.         for i in range(1, 50000, 500):
  540.             key = "size%s" % i
  541.             #print "before ", i,
  542.             d.put(key, "1" * i)
  543.             #print "after",
  544.             assert d.get_size(key) == i
  545.             #print "done"
  546.  
  547.     #----------------------------------------
  548.  
  549.     def test06_Truncate(self):
  550.         if db.version() < (3,3):
  551.             # truncate is a feature of BerkeleyDB 3.3 and above
  552.             return
  553.  
  554.         d = self.d
  555.         if verbose:
  556.             print '\n', '-=' * 30
  557.             print "Running %s.test99_Truncate..." % self.__class__.__name__
  558.  
  559.         d.put("abcde", "ABCDE");
  560.         num = d.truncate()
  561.         assert num >= 1, "truncate returned <= 0 on non-empty database"
  562.         num = d.truncate()
  563.         assert num == 0, "truncate on empty DB returned nonzero (%r)" % (num,)
  564.  
  565.     #----------------------------------------
  566.  
  567.  
  568. #----------------------------------------------------------------------
  569.  
  570.  
  571. class BasicBTreeTestCase(BasicTestCase):
  572.     dbtype = db.DB_BTREE
  573.  
  574.  
  575. class BasicHashTestCase(BasicTestCase):
  576.     dbtype = db.DB_HASH
  577.  
  578.  
  579. class BasicBTreeWithThreadFlagTestCase(BasicTestCase):
  580.     dbtype = db.DB_BTREE
  581.     dbopenflags = db.DB_THREAD
  582.  
  583.  
  584. class BasicHashWithThreadFlagTestCase(BasicTestCase):
  585.     dbtype = db.DB_HASH
  586.     dbopenflags = db.DB_THREAD
  587.  
  588.  
  589. class BasicWithEnvTestCase(BasicTestCase):
  590.     dbopenflags = db.DB_THREAD
  591.     useEnv = 1
  592.     envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
  593.  
  594.     #----------------------------------------
  595.  
  596.     def test07_EnvRemoveAndRename(self):
  597.         if not self.env:
  598.             return
  599.  
  600.         if verbose:
  601.             print '\n', '-=' * 30
  602.             print "Running %s.test07_EnvRemoveAndRename..." % self.__class__.__name__
  603.  
  604.         # can't rename or remove an open DB
  605.         self.d.close()
  606.  
  607.         newname = self.filename + '.renamed'
  608.         self.env.dbrename(self.filename, None, newname)
  609.         self.env.dbremove(newname)
  610.  
  611.     # dbremove and dbrename are in 4.1 and later
  612.     if db.version() < (4,1):
  613.         del test07_EnvRemoveAndRename
  614.  
  615.     #----------------------------------------
  616.  
  617. class BasicBTreeWithEnvTestCase(BasicWithEnvTestCase):
  618.     dbtype = db.DB_BTREE
  619.  
  620.  
  621. class BasicHashWithEnvTestCase(BasicWithEnvTestCase):
  622.     dbtype = db.DB_HASH
  623.  
  624.  
  625. #----------------------------------------------------------------------
  626.  
  627. class BasicTransactionTestCase(BasicTestCase):
  628.     dbopenflags = db.DB_THREAD | db.DB_AUTO_COMMIT
  629.     useEnv = 1
  630.     envflags = (db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK |
  631.                 db.DB_INIT_TXN)
  632.     envsetflags = db.DB_AUTO_COMMIT
  633.  
  634.  
  635.     def tearDown(self):
  636.         self.txn.commit()
  637.         BasicTestCase.tearDown(self)
  638.  
  639.  
  640.     def populateDB(self):
  641.         txn = self.env.txn_begin()
  642.         BasicTestCase.populateDB(self, _txn=txn)
  643.  
  644.         self.txn = self.env.txn_begin()
  645.  
  646.  
  647.     def test06_Transactions(self):
  648.         d = self.d
  649.         if verbose:
  650.             print '\n', '-=' * 30
  651.             print "Running %s.test06_Transactions..." % self.__class__.__name__
  652.  
  653.         assert d.get('new rec', txn=self.txn) == None
  654.         d.put('new rec', 'this is a new record', self.txn)
  655.         assert d.get('new rec', txn=self.txn) == 'this is a new record'
  656.         self.txn.abort()
  657.         assert d.get('new rec') == None
  658.  
  659.         self.txn = self.env.txn_begin()
  660.  
  661.         assert d.get('new rec', txn=self.txn) == None
  662.         d.put('new rec', 'this is a new record', self.txn)
  663.         assert d.get('new rec', txn=self.txn) == 'this is a new record'
  664.         self.txn.commit()
  665.         assert d.get('new rec') == 'this is a new record'
  666.  
  667.         self.txn = self.env.txn_begin()
  668.         c = d.cursor(self.txn)
  669.         rec = c.first()
  670.         count = 0
  671.         while rec is not None:
  672.             count = count + 1
  673.             if verbose and count % 100 == 0:
  674.                 print rec
  675.             rec = c.next()
  676.         assert count == self._numKeys+1
  677.  
  678.         c.close()                # Cursors *MUST* be closed before commit!
  679.         self.txn.commit()
  680.  
  681.         # flush pending updates
  682.         try:
  683.             self.env.txn_checkpoint (0, 0, 0)
  684.         except db.DBIncompleteError:
  685.             pass
  686.  
  687.         if db.version() >= (4,0):
  688.             statDict = self.env.log_stat(0);
  689.             assert statDict.has_key('magic')
  690.             assert statDict.has_key('version')
  691.             assert statDict.has_key('cur_file')
  692.             assert statDict.has_key('region_nowait')
  693.  
  694.         # must have at least one log file present:
  695.         logs = self.env.log_archive(db.DB_ARCH_ABS | db.DB_ARCH_LOG)
  696.         assert logs != None
  697.         for log in logs:
  698.             if verbose:
  699.                 print 'log file: ' + log
  700.         if db.version() >= (4,2):
  701.             logs = self.env.log_archive(db.DB_ARCH_REMOVE)
  702.             assert not logs
  703.  
  704.         self.txn = self.env.txn_begin()
  705.  
  706.     #----------------------------------------
  707.  
  708.     def test07_TxnTruncate(self):
  709.         if db.version() < (3,3):
  710.             # truncate is a feature of BerkeleyDB 3.3 and above
  711.             return
  712.  
  713.         d = self.d
  714.         if verbose:
  715.             print '\n', '-=' * 30
  716.             print "Running %s.test07_TxnTruncate..." % self.__class__.__name__
  717.  
  718.         d.put("abcde", "ABCDE");
  719.         txn = self.env.txn_begin()
  720.         num = d.truncate(txn)
  721.         assert num >= 1, "truncate returned <= 0 on non-empty database"
  722.         num = d.truncate(txn)
  723.         assert num == 0, "truncate on empty DB returned nonzero (%r)" % (num,)
  724.         txn.commit()
  725.  
  726.     #----------------------------------------
  727.  
  728.     def test08_TxnLateUse(self):
  729.         txn = self.env.txn_begin()
  730.         txn.abort()
  731.         try:
  732.             txn.abort()
  733.         except db.DBError, e:
  734.             pass
  735.         else:
  736.             raise RuntimeError, "DBTxn.abort() called after DB_TXN no longer valid w/o an exception"
  737.  
  738.         txn = self.env.txn_begin()
  739.         txn.commit()
  740.         try:
  741.             txn.commit()
  742.         except db.DBError, e:
  743.             pass
  744.         else:
  745.             raise RuntimeError, "DBTxn.commit() called after DB_TXN no longer valid w/o an exception"
  746.  
  747.  
  748. class BTreeTransactionTestCase(BasicTransactionTestCase):
  749.     dbtype = db.DB_BTREE
  750.  
  751. class HashTransactionTestCase(BasicTransactionTestCase):
  752.     dbtype = db.DB_HASH
  753.  
  754.  
  755.  
  756. #----------------------------------------------------------------------
  757.  
  758. class BTreeRecnoTestCase(BasicTestCase):
  759.     dbtype     = db.DB_BTREE
  760.     dbsetflags = db.DB_RECNUM
  761.  
  762.     def test07_RecnoInBTree(self):
  763.         d = self.d
  764.         if verbose:
  765.             print '\n', '-=' * 30
  766.             print "Running %s.test07_RecnoInBTree..." % self.__class__.__name__
  767.  
  768.         rec = d.get(200)
  769.         assert type(rec) == type(())
  770.         assert len(rec) == 2
  771.         if verbose:
  772.             print "Record #200 is ", rec
  773.  
  774.         c = d.cursor()
  775.         c.set('0200')
  776.         num = c.get_recno()
  777.         assert type(num) == type(1)
  778.         if verbose:
  779.             print "recno of d['0200'] is ", num
  780.  
  781.         rec = c.current()
  782.         assert c.set_recno(num) == rec
  783.  
  784.         c.close()
  785.  
  786.  
  787.  
  788. class BTreeRecnoWithThreadFlagTestCase(BTreeRecnoTestCase):
  789.     dbopenflags = db.DB_THREAD
  790.  
  791. #----------------------------------------------------------------------
  792.  
  793. class BasicDUPTestCase(BasicTestCase):
  794.     dbsetflags = db.DB_DUP
  795.  
  796.     def test08_DuplicateKeys(self):
  797.         d = self.d
  798.         if verbose:
  799.             print '\n', '-=' * 30
  800.             print "Running %s.test08_DuplicateKeys..." % \
  801.                   self.__class__.__name__
  802.  
  803.         d.put("dup0", "before")
  804.         for x in "The quick brown fox jumped over the lazy dog.".split():
  805.             d.put("dup1", x)
  806.         d.put("dup2", "after")
  807.  
  808.         data = d.get("dup1")
  809.         assert data == "The"
  810.         if verbose:
  811.             print data
  812.  
  813.         c = d.cursor()
  814.         rec = c.set("dup1")
  815.         assert rec == ('dup1', 'The')
  816.  
  817.         next = c.next()
  818.         assert next == ('dup1', 'quick')
  819.  
  820.         rec = c.set("dup1")
  821.         count = c.count()
  822.         assert count == 9
  823.  
  824.         next_dup = c.next_dup()
  825.         assert next_dup == ('dup1', 'quick')
  826.  
  827.         rec = c.set('dup1')
  828.         while rec is not None:
  829.             if verbose:
  830.                 print rec
  831.             rec = c.next_dup()
  832.  
  833.         c.set('dup1')
  834.         rec = c.next_nodup()
  835.         assert rec[0] != 'dup1'
  836.         if verbose:
  837.             print rec
  838.  
  839.         c.close()
  840.  
  841.  
  842.  
  843. class BTreeDUPTestCase(BasicDUPTestCase):
  844.     dbtype = db.DB_BTREE
  845.  
  846. class HashDUPTestCase(BasicDUPTestCase):
  847.     dbtype = db.DB_HASH
  848.  
  849. class BTreeDUPWithThreadTestCase(BasicDUPTestCase):
  850.     dbtype = db.DB_BTREE
  851.     dbopenflags = db.DB_THREAD
  852.  
  853. class HashDUPWithThreadTestCase(BasicDUPTestCase):
  854.     dbtype = db.DB_HASH
  855.     dbopenflags = db.DB_THREAD
  856.  
  857.  
  858. #----------------------------------------------------------------------
  859.  
  860. class BasicMultiDBTestCase(BasicTestCase):
  861.     dbname = 'first'
  862.  
  863.     def otherType(self):
  864.         if self.dbtype == db.DB_BTREE:
  865.             return db.DB_HASH
  866.         else:
  867.             return db.DB_BTREE
  868.  
  869.     def test09_MultiDB(self):
  870.         d1 = self.d
  871.         if verbose:
  872.             print '\n', '-=' * 30
  873.             print "Running %s.test09_MultiDB..." % self.__class__.__name__
  874.  
  875.         d2 = db.DB(self.env)
  876.         d2.open(self.filename, "second", self.dbtype,
  877.                 self.dbopenflags|db.DB_CREATE)
  878.         d3 = db.DB(self.env)
  879.         d3.open(self.filename, "third", self.otherType(),
  880.                 self.dbopenflags|db.DB_CREATE)
  881.  
  882.         for x in "The quick brown fox jumped over the lazy dog".split():
  883.             d2.put(x, self.makeData(x))
  884.  
  885.         for x in string.letters:
  886.             d3.put(x, x*70)
  887.  
  888.         d1.sync()
  889.         d2.sync()
  890.         d3.sync()
  891.         d1.close()
  892.         d2.close()
  893.         d3.close()
  894.  
  895.         self.d = d1 = d2 = d3 = None
  896.  
  897.         self.d = d1 = db.DB(self.env)
  898.         d1.open(self.filename, self.dbname, flags = self.dbopenflags)
  899.         d2 = db.DB(self.env)
  900.         d2.open(self.filename, "second",  flags = self.dbopenflags)
  901.         d3 = db.DB(self.env)
  902.         d3.open(self.filename, "third", flags = self.dbopenflags)
  903.  
  904.         c1 = d1.cursor()
  905.         c2 = d2.cursor()
  906.         c3 = d3.cursor()
  907.  
  908.         count = 0
  909.         rec = c1.first()
  910.         while rec is not None:
  911.             count = count + 1
  912.             if verbose and (count % 50) == 0:
  913.                 print rec
  914.             rec = c1.next()
  915.         assert count == self._numKeys
  916.  
  917.         count = 0
  918.         rec = c2.first()
  919.         while rec is not None:
  920.             count = count + 1
  921.             if verbose:
  922.                 print rec
  923.             rec = c2.next()
  924.         assert count == 9
  925.  
  926.         count = 0
  927.         rec = c3.first()
  928.         while rec is not None:
  929.             count = count + 1
  930.             if verbose:
  931.                 print rec
  932.             rec = c3.next()
  933.         assert count == 52
  934.  
  935.  
  936.         c1.close()
  937.         c2.close()
  938.         c3.close()
  939.  
  940.         d2.close()
  941.         d3.close()
  942.  
  943.  
  944.  
  945. # Strange things happen if you try to use Multiple DBs per file without a
  946. # DBEnv with MPOOL and LOCKing...
  947.  
  948. class BTreeMultiDBTestCase(BasicMultiDBTestCase):
  949.     dbtype = db.DB_BTREE
  950.     dbopenflags = db.DB_THREAD
  951.     useEnv = 1
  952.     envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
  953.  
  954. class HashMultiDBTestCase(BasicMultiDBTestCase):
  955.     dbtype = db.DB_HASH
  956.     dbopenflags = db.DB_THREAD
  957.     useEnv = 1
  958.     envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
  959.  
  960.  
  961. #----------------------------------------------------------------------
  962. #----------------------------------------------------------------------
  963.  
  964. def test_suite():
  965.     suite = unittest.TestSuite()
  966.  
  967.     suite.addTest(unittest.makeSuite(VersionTestCase))
  968.     suite.addTest(unittest.makeSuite(BasicBTreeTestCase))
  969.     suite.addTest(unittest.makeSuite(BasicHashTestCase))
  970.     suite.addTest(unittest.makeSuite(BasicBTreeWithThreadFlagTestCase))
  971.     suite.addTest(unittest.makeSuite(BasicHashWithThreadFlagTestCase))
  972.     suite.addTest(unittest.makeSuite(BasicBTreeWithEnvTestCase))
  973.     suite.addTest(unittest.makeSuite(BasicHashWithEnvTestCase))
  974.     suite.addTest(unittest.makeSuite(BTreeTransactionTestCase))
  975.     suite.addTest(unittest.makeSuite(HashTransactionTestCase))
  976.     suite.addTest(unittest.makeSuite(BTreeRecnoTestCase))
  977.     suite.addTest(unittest.makeSuite(BTreeRecnoWithThreadFlagTestCase))
  978.     suite.addTest(unittest.makeSuite(BTreeDUPTestCase))
  979.     suite.addTest(unittest.makeSuite(HashDUPTestCase))
  980.     suite.addTest(unittest.makeSuite(BTreeDUPWithThreadTestCase))
  981.     suite.addTest(unittest.makeSuite(HashDUPWithThreadTestCase))
  982.     suite.addTest(unittest.makeSuite(BTreeMultiDBTestCase))
  983.     suite.addTest(unittest.makeSuite(HashMultiDBTestCase))
  984.  
  985.     return suite
  986.  
  987.  
  988. if __name__ == '__main__':
  989.     unittest.main(defaultTest='test_suite')
  990.